library SniperScope initializer init requires LegacySystem


	private function Trig_Sniper_Scope_Begin_Conditions takes nothing returns boolean
		return GetSpellAbilityId() == 'A03R'
	endfunction

	private function SniperScopeScan takes nothing returns boolean
		return GetUnitPointValue(GetFilterUnit())==50 and GetWidgetLife(GetFilterUnit())>0.405 and GetUnitTypeId(GetFilterUnit())!='e00C'
	endfunction

	private function SniperScopeClassAScan takes location l returns nothing
		 local group g = AMGetUnitsInRange(800, l, Condition(function SniperScopeScan))
		 local real x = GetLocationX(l)
		 local real y = GetLocationY(l)   
		 local real dx
		 local real dy
		 local unit classA
		 local integer scan = 0
		 loop
				set classA = FirstOfGroup(g)
				exitwhen classA==null
				set dx = GetUnitX(classA) - x
				set dy = GetUnitY(classA) - y
				if scan<6 then
					 call PingMinimapEx(GetUnitX(classA),GetUnitY(classA),3.0,242,51,51,false)
					 set scan = scan + 1
				endif
				call GroupRemoveUnit(g,classA)
		 endloop      
		 call DestroyGroup(g)
		 set g = null
		 set classA = null
	endfunction

	private function SniperScopeChannelCheck takes nothing returns nothing
		 local timer t = GetExpiredTimer()
		 local unit caster = getUnit(t,"caster")
		 local unit sightaura = null

		 local real xc = GetUnitX(caster)
		 local real yc = GetUnitY(caster)
		 local real xt = getReal(t,"oldx")
		 local real yt = getReal(t,"oldy")
		
		 local real d = xc-xt+yc-yt // if new y or new x changed, then sniper has moved
		 
		 if(d != 0 ) then
			set sightaura = getUnit(caster, "sniper_scope_effect")  
			 call FlushHandleLocals(sightaura)
			 call RemoveUnit(sightaura)

			 if GetWidgetLife(caster)>0.405 then      // remove all bonus abilites
				call UnitRemoveAbility(caster,'A06K')
				call UnitRemoveAbility(caster,'A03Q')
				call UnitRemoveAbility(caster,'A07K')
				if (GetUnitAbilityLevel(caster,'A06Z') >= 2) then
					  call UnitAddAbility(caster,'A08O') // add back 20 sec camo
				endif
			 endif

			 call putBoolean(caster,"is_scoping",false)
			 set caster = null
			 set sightaura = null   
			 call FlushHandleLocals(t)
			 call ReleaseTimer(t)
			 set t = null
		 else
			 set t = null
			 set caster = null
		 endif
	endfunction

	private function SniperOpticalScope takes nothing returns nothing

		local unit caster = GetTriggerUnit()
		local unit scope_sight
		local integer snipertraininglevel = GetUnitAbilityLevel(caster,'A06Z')
		local integer scopelevel = GetUnitAbilityLevel(caster,'A03R')
		local location target = GetSpellTargetLoc()
		local location origin = GetUnitLoc(caster)
		local real d =  RAbsBJ(DistanceBetweenPoints(target,origin))
		local integer i = 2000+scopelevel*300
		local timer t 
	  
		if( d>=i ) then     
			 call RemoveLocation(target)
			 call RemoveLocation(origin)
			 call IssueImmediateOrderBJ( caster, "stop" )
			 set caster = null
			 set scope_sight = null
			 set origin = null
			 set target = null
			 set t = null
			 return
		endif  
		if( visibleBJ(origin,target,100.0) == false) then
			 call RemoveLocation(target)
			 call RemoveLocation(origin)
			 call IssueImmediateOrderBJ( caster, "stop" )
			 set caster = null
			 set scope_sight = null
			 set origin = null
			 set target = null
			 set t = null
			 return
		endif

		if snipertraininglevel>=3 then
			 call SniperScopeClassAScan(target)       
		endif
		
		// check if old scope sight exists
		set scope_sight = getUnit(caster,"sniper_scope_effect")
		if(scope_sight!= null) then 
		   // if the unit is not null then dont add abilities because sniper is already casting scope.
		   call FlushHandleLocals(scope_sight)
		   call RemoveUnit(scope_sight)
		   set t = getTimer(scope_sight,"t")
		   call FlushHandleLocals(t)
		   call ReleaseTimer(t)
		else 
		   // if the unit is null then the sniper just began casting scope
		   if (GetUnitAbilityLevel(caster,'A08O') >0) then
			   call UnitRemoveAbility(caster,'A08O') // remove 20 sec camo
		   endif 
		   call UnitAddAbility(caster,'A06K') //Camoflouge (Sniper Scope)
		   call UnitAddAbility(caster,'A07K') // sight reduction
		   call UnitAddAbility(caster,'A03Q') //+60*spell level dmg
		   set i = 1
		   loop
			  exitwhen i >= scopelevel
			  call IncUnitAbilityLevel(caster,'A03Q')
			  set i = i + 1
		   endloop
		endif  

		// create new scope sight on cast
		set scope_sight =  CreateUnit(GetOwningPlayer(caster),'e00T',GetLocationX(target),GetLocationY(target),0.0)
		if(scopelevel >= 3) then
			call UnitAddAbility(scope_sight,'A06B') // true sight
		endif
		call putUnit(caster,"sniper_scope_effect",scope_sight)
	 
		// timer to check caster movement
		set t = CreateTimer()
		call putUnit(t,"caster",caster)
		call putReal(t,"oldx",GetLocationX(origin))
		call putReal(t,"oldy",GetLocationY(origin))
		call putTimer(scope_sight,"t",t)
		call putBoolean(caster,"is_scoping", true)
		call TimerStart(t,0.4,true,function SniperScopeChannelCheck)
	   
		call TriggerSleepAction(2.1)

		// order hold position to prevent idiot pathing incase target hides from scope
		if( getBoolean(caster,"is_scoping") == true) then
			 call IssueImmediateOrderBJ( caster, "holdposition" )
		endif

		call RemoveLocation(target)
		call RemoveLocation(origin)
		set origin = null
		set target = null
		set scope_sight = null
		set caster = null
		set t = null
	endfunction

	private function init takes nothing returns nothing
		local trigger t
		set t = CreateTrigger(  )
		call TriggerRegisterAnyUnitEventBJ( t,  EVENT_PLAYER_UNIT_SPELL_EFFECT  )
		call TriggerAddCondition( t, Condition( function Trig_Sniper_Scope_Begin_Conditions ) )
		call TriggerAddAction( t, function SniperOpticalScope )
	endfunction




endlibrary